<template>
  <div class="audition11">
    <h3>什么是闭包？</h3>
    <p>闭包：可以读取其他函数内部变量的函数</p>
    <v-md-preview :text="text1" />
    <p>这里的fn2就是一个闭包</p>
    <p>既然fn2可以读取fn1内部的变量，此时，把fn2从fn1中返回，我们在外部就可以很方便的使用fn2函数读取到fn1内部的变量了</p>
    <v-md-preview :text="text2" />
    <hr>
    <h3>闭包的用途是什么？</h3>
    <p>根据闭包的定义，闭包的其中一个用途就是读取函数内部的变量</p>
    <p>闭包的另一个作用是，让函数内部的变量始终保存在内存中</p>
    <p>示例：</p>
    <v-md-preview :text="text3" />
    <p>普通函数的变量并没有被保存起来，所以示例中变量自增后，再次执行函数，变量也不会输出2</p>
    <p>而闭包函数体，当把fn1()赋值给变量f时，fn2被保存在了内存中，作为fn2的父函数，fn1也被保存在内存中，变量自增后，会输出2</p>
    <hr>
    <h3>闭包的this指向</h3>
    <p>如果内部函数没有使用箭头函数定义，则this对象会在运行时绑定到执行函数的上下文</p>
    <p>如果在全局函数中调用，则this在非严格模式下指向window，在严格模式下等于undefined</p>
    <p>如果作为某个对象的方法调用，则this等于这个对象</p>
    <p>匿名函数在这种情况下不会绑定到某个对象，而是指向window，在严格模式下指向undefined</p>
    <p>例题1</p>
    <v-md-preview :text="text4" />
    <p>例题2</p>
    <v-md-preview :text="text5" />
    <hr>
    <h3>闭包的内存泄露问题</h3>
    <p>比如在IE9之前的引用计数的垃圾回收机制中使用闭包</p>
    <code class="code">
      function f() {<br />
        <span class="indient">let btn = document.querysolector('button')</span><br />
        <span class="indient">btn.onclick = () => console.log(btn.id)</span><br />
      }
    </code>
    <p>btn对象一直被引用，引用计算无法归零，导致无法被垃圾回收</p>
    <p>此时就要在使用后手动处理</p>
    <code class="code">
      function f() {<br />
        <span class="indient">let btn = document.querysolector('button')</span><br />
        <span class="indient">let id = btn.id</span><br />
        <span class="indient">btn.onclick = () => console.log(btn.id)</span><br />
        <span class="indient">btn = null</span><br />
      }
    </code>
  </div>
</template>

<script>
const prefix = '``` js'
const suffix = '```'
export default {
  name: 'Audition11',
  data() {
    return {
      text1: `${prefix}
        function fn1() {
          var a = 1
          function fn2() {
            console.log(a)
          }
        }
      \n${suffix}`,
      text2: `${prefix}
        function fn1() {
          var a = 1
          function fn2() {
            console.log(a)
          }
          return fn2
        }
      \n${suffix}`,
      text3: `${prefix}
        // 普通函数
        function fn1 () {
          var n = 1
          addN =  function() {n++}
          console.log(n)
        }
        fn1()
        addN()
        fn1()
        // 结果
        1  1

        // 闭包
        function fn1 () {
          var n = 1
          addN =  function() {n++}
          return function() {
            console.log(n)
          }
        }
        var f = fn1()
        f()
        addN()
        f()
        // 结果
        1  2
      \n${suffix}`,
      text4: `${prefix}
        var name = "The Window";
        var object = {
          name: "My Object",
          getNameFunc: function () {
            var name = 'dilireba'
            console.log(1, this.name)
            return function () {
              return this.name;
            };
          }
        };
        console.log(object.getNameFunc()());
      \n${suffix}`,
      text5: `${prefix}
        var name = "The Window";
        var object = {
          name: "My Object",
          getNameFunc: function () {
            var name = 'dilireba'
            var that = this
            console.log(1, that.name)
            return function () {
              return that.name;
            };
          }
        };
        console.log(object.getNameFunc()());
      \n${suffix}`,
    }
  }
}
</script>

<style>

</style>